package com.cnap.service.impl;

import cn.hutool.core.io.FileUtil;
import com.cnap.CnapApplicationTests;
import com.cnap.config.FileConfig;
import com.cnap.db.entity.FileInfoPO;
import com.cnap.db.entity.PatchInfoPO;
import com.cnap.db.mapper.FileMapper;
import com.cnap.model.exception.JsonException;
import com.cnap.model.file.FileInitReq;
import com.cnap.model.file.MergeReq;
import com.cnap.model.file.PatchRes;
import com.cnap.model.file.UploadPatchReq;
import com.cnap.service.FileService;
import com.cnap.service.ProgressService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.mock.web.MockMultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * <类文件描述>
 *
 * @author xc
 **/
class FileServiceImplTest extends CnapApplicationTests {

    @MockBean
    private FileMapper fileMapperMock;
    @MockBean
    private ProgressService progressServiceMock;

    @Autowired
    private FileConfig fileConfig;
    @Autowired
    private FileService fileService;

    @Test
    void initFileInfo() {
        Mockito.when(fileMapperMock.saveFileInfo(Mockito.any())).thenReturn(1);

        FileInitReq fileInitReq = new FileInitReq();
        fileInitReq.setName("test-file.zip");
        fileInitReq.setPatchNums(3);
        fileInitReq.setTotalSize(1204);

        String id = fileService.initFileInfo(fileInitReq);

        Assertions.assertNotNull(id);
    }

    @Test
    void initFileInfoWithDbError() {
        Mockito.when(fileMapperMock.saveFileInfo(Mockito.any())).thenReturn(0);

        FileInitReq fileInitReq = new FileInitReq();
        fileInitReq.setName("test-file.zip");
        fileInitReq.setPatchNums(3);
        fileInitReq.setTotalSize(1204);

        Assertions.assertThrows(JsonException.class, ()->{
            fileService.initFileInfo(fileInitReq);
        });
    }

    @Test
    void testInitFileInfo() {
        Mockito.when(fileMapperMock.saveFileInfo(Mockito.any())).thenReturn(1);
        String id = "1";
        FileInitReq fileInitReq = new FileInitReq();
        fileInitReq.setName("test-file.zip");
        fileInitReq.setPatchNums(3);
        fileInitReq.setTotalSize(1204);

        String id1 = fileService.initFileInfo(fileInitReq, id);

        Assertions.assertEquals(id, id1);
    }

    @Test
    void testInitFileInfoWithDbError() {
        Mockito.when(fileMapperMock.saveFileInfo(Mockito.any())).thenReturn(0);
        String id = "1";
        FileInitReq fileInitReq = new FileInitReq();
        fileInitReq.setName("test-file.zip");
        fileInitReq.setPatchNums(3);
        fileInitReq.setTotalSize(1204);

        Assertions.assertThrows(JsonException.class, ()->{
            fileService.initFileInfo(fileInitReq, id);
        });
    }

    @Test
    void uploadPatchWithNoParentFileInfo() {
        MockMultipartFile mockMultipartFile = new MockMultipartFile("test_0", "test".getBytes(StandardCharsets.UTF_8));
        Mockito.when(fileMapperMock.selectById("12")).thenReturn(null);
        UploadPatchReq req = new UploadPatchReq();
        req.setParentId("12");
        Assertions.assertThrows(JsonException.class, ()->{
            fileService.uploadPatch(req, mockMultipartFile);
        });
    }

    @Test
    void uploadPatch() {
        FileInfoPO fileInfoPO = new FileInfoPO();
        fileInfoPO.setId("123");
        fileInfoPO.setPatchNums(1);
        fileInfoPO.setTotalSize(100);
        fileInfoPO.setFileName("test.zip");
        MockMultipartFile mockMultipartFile = new MockMultipartFile("test_0", "test".getBytes(StandardCharsets.UTF_8));

        Mockito.when(fileMapperMock.selectById("123")).thenReturn(fileInfoPO);
        Mockito.when(fileMapperMock.selectByParentIdAndIndex("123", 0)).thenReturn(null);
        Mockito.when(fileMapperMock.savePatchInfo(Mockito.any())).thenReturn(1);

        UploadPatchReq req = new UploadPatchReq();
        req.setParentId("12");
        req.setFileName("test.zip");
        req.setIndex(0);
        req.setPatchSize(100);
        req.setParentId("123");

        PatchRes res = fileService.uploadPatch(req, mockMultipartFile);

        Assertions.assertNotNull(res);
    }

    @Test
    void mergePatchFile() throws IOException {
        String os = System.getProperty("os.name");
        if (os != null && os.toLowerCase(Locale.ROOT).startsWith("windows")) {
            System.out.println("windows");
        } else {
            fileConfig.setPath("/var/jenkins_home/workspace");
        }
        File file = new File(fileService.getSavePath("1"));
        if (!file.exists()) {
            file.mkdir();
        }
        File file1 = new File(fileService.getSavePath("1") + File.separator + "1_0");
        if (!file1.exists()) {
            System.out.println(fileService.getSavePath("1") + File.separator + "1_0");
            file1.createNewFile();
            FileOutputStream fileOutputStream = new FileOutputStream(file1);
            fileOutputStream.write("123".getBytes(StandardCharsets.UTF_8));
            fileOutputStream.close();
        }
        FileInfoPO fileInfoPO = new FileInfoPO();
        fileInfoPO.setId("1");
        fileInfoPO.setPatchNums(1);
        fileInfoPO.setTotalSize(1000);
        fileInfoPO.setFileName("test.zip");

        List<PatchInfoPO> patchInfoPOS = new ArrayList<>();
        PatchInfoPO patchInfoPO = new PatchInfoPO();
        patchInfoPO.setIndex(0);
        patchInfoPO.setParentId("1");
        patchInfoPO.setPatchSize(1000);
        patchInfoPOS.add(patchInfoPO);

        Mockito.when(progressServiceMock.updateProgress(Mockito.any())).thenReturn(true);
        Mockito.when(fileMapperMock.selectById("1")).thenReturn(fileInfoPO);
        Mockito.when(fileMapperMock.selectByParentId("1")).thenReturn(patchInfoPOS);
        //Mockito.mockStatic(TokenUtils.class).when(TokenUtils::getUserName).thenReturn("admin");
        fileUtilMockedStatic.when(()->FileUtil.exist(Mockito.anyString())).thenReturn(false);


        MergeReq me = new MergeReq();
        me.setParentId("1");
        me.setTotalSize(1000);
        me.setMd5("");

        Assertions.assertDoesNotThrow(()->{
            fileService.mergePatchFile(me);
            Thread.sleep(30000);
        });
        FileUtil.del(fileService.getSavePath("1"));
    }

    @Test
    void deleteFileInfoAndPatchInfoById() {
        String parentId = "1";
        Mockito.when(fileMapperMock.deleteFileInfoById(parentId)).thenReturn(1);
        List<PatchInfoPO> patchInfoPOS = new ArrayList<>();
        Mockito.when(fileMapperMock.selectByParentId(parentId)).thenReturn(patchInfoPOS);
        Mockito.when(fileMapperMock.deletePatchByParentId(parentId)).thenReturn(0);

        boolean result = fileService.deleteFileInfoAndPatchInfoById(parentId);

        Assertions.assertTrue(result);
    }

    @Test
    void getSavePath() {
        String path = fileService.getSavePath("12");
        Assertions.assertNotNull(path);
    }
}